﻿using Soft.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Soft.Service
{
    /// <summary>
    /// 封装一个功能项的表示
    /// </summary>
    public sealed class ProcessItem : ErrorResponse
    {


        /// <summary>
        /// job运行的方法
        /// </summary>
        public JobServiceMode JobServiceMode { get; private set; }


        /// <summary>
        /// 封装要调用的方法
        /// </summary>
        public MethodCallInfo Method { get; private set; }


        /// <summary>
        /// 远程job的类型
        /// </summary>
        public Type JobClassType { get; private set; }



        /// <summary>
        /// 方法的签名
        /// </summary>
        public FunctionSign FunctionSign { get; private set; }


        /// <summary>
        /// job实例
        /// </summary>
        public JobInstance Instance { get; set; }


        /// <summary>
        /// job是否在运行
        /// </summary>
        public bool Running { get; set; }


        /// <summary>
        /// 封装一个功能项的表示
        /// </summary>
        /// <param name="functionSign">方法签名</param>
        /// <param name="mode">job的运行方法 实例化、单利、作为服务、作为job   </param>
        /// <param name="method">封装要调用的方法</param>
        /// <param name="remotingObjectType">要调用远程类的类型</param>
        /// <param name="instance">参数列表</param>
        public ProcessItem(FunctionSign functionSign, JobServiceMode mode, MethodCallInfo method, Type remotingObjectType, JobInstance instance)
        {
            this.FunctionSign = functionSign;
            this.JobServiceMode = mode;
            this.Method = method;
            this.JobClassType = remotingObjectType;
            this.Instance = instance;
        }


        /// <summary>
        ///  Invoke调用
        /// </summary>
        /// <param name="jsonParam"></param>
        /// <param name="debug"></param>
        /// <returns></returns>
        public InvokeResult Invoke(string jsonParam, bool debug)
        {
            InvokeResult invokeResult = new InvokeResult();
            BaseJob baseJob = null;
            Stopwatch stopwatch = null;
            if (debug)
            {
                stopwatch = new Stopwatch();
                stopwatch.Start();
            }
            try
            {
                if (this.JobServiceMode == JobServiceMode.Dynamic)
                {
                    baseJob = (BaseJob)Activator.CreateInstance(this.JobClassType);
                }
                else
                {
                    baseJob = this.Instance.Instance;
                }
                baseJob.ExecuteMethodCallInstruction = this.Instance.ExecuteMethodHandle;
            }
            catch (Exception innerException)
            {
                Exception ex = new InternalSystemException(string.Format("在构建对象实例时发生错误。({0})", this.FunctionSign), this, innerException);
                this.OnError(ex);
                invokeResult.AddError(ex, null);
                return invokeResult;
            }
            object obj = null;
            List<object> list = new List<object>();
            if (!string.IsNullOrWhiteSpace(jsonParam))
            {
                InvokeParameCollection invokeParameCollection = JsonConvertHelper.FormJson<InvokeParameCollection>(jsonParam);
                if (invokeParameCollection == null)
                {
                    InternalSystemException ex2 = new InternalSystemException(string.Format("在获取客户端请求数据时，将转换 json 数据转换成 {0} 类型的实例时发生了错误。功能码：{1}。这个 json 数据是：{2}", typeof(InvokeParameCollection).FullName, this.FunctionSign, jsonParam), this, null);
                    this.OnError(ex2);
                    invokeResult.AddError(ex2, null);
                    return invokeResult;
                }
                using (List<ParameterInfo>.Enumerator enumerator = this.Method.MethodParamsterInfoList.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        ParameterInfo param = enumerator.Current;
                        object item = null;
                        InvokeParameItem invokeParameItem = invokeParameCollection.Find((InvokeParameItem e) => e.Name == param.Name);
                        if (invokeParameItem == null)
                        {
                            if (!param.HasDefaultValue)
                            {
                                Exception ex3 = new Exception(string.Format("缺少输入参数 '{0}'。({1})", param.Name, this.FunctionSign));
                                this.OnError(ex3);
                                invokeResult.AddError(ex3, null);
                                return invokeResult;
                            }
                            item = param.DefaultValue;
                        }
                        else
                        {
                            try
                            {
                                item = JsonConvertHelper.FormJson(invokeParameItem.Value, Type.GetType(invokeParameItem.ValueType));
                            }
                            catch (Exception innerException2)
                            {
                                Exception ex4 = new Exception(string.Format("获取参数值时出现错误，将“{0}”转换成“{1}”类型时失败。所在功能号：{2}.", invokeParameItem.Value ?? "null", invokeParameItem.ValueType, this.FunctionSign), innerException2);
                                this.OnError(ex4);
                                invokeResult.AddError(ex4, null);
                                return invokeResult;
                            }
                        }
                        list.Add(item);
                    }
                }
            }
            MethodInfo left = null;
            try
            {
                if (this.Method.MethodParamsterInfoList.Count > 0)
                {
                    left = this.JobClassType.GetMethod(this.Method.MethodName, this.Method.MethodParamsterInfoList.ConvertAll<Type>((ParameterInfo e) => e.ParameterType).ToArray());
                }
                else
                {
                    left = this.JobClassType.GetMethod(this.Method.MethodName, Type.EmptyTypes);
                }
            }
            catch (Exception innerException3)
            {
                Exception ex5 = new Exception(string.Concat(new string[]
                {
                    "获取对象“",
                    this.JobClassType.FullName,
                    "”的“",
                    this.Method.MethodName,
                    "”方法时发生错误。请确认所在的DLL文件。"
                }), innerException3);
                this.OnError(ex5);
                invokeResult.AddError(ex5, null);
                return invokeResult;
            }
            if (left == null)
            {
                string str = "使用方法名";
                if (this.Method.MethodParamsterInfoList.Count > 0)
                {
                    str = str + "和输入参数“" + string.Join(", ", this.Method.MethodParamsterInfoList.ConvertAll<string>((ParameterInfo e) => e.ParameterType.FullName).ToArray()) + "”";
                }
                str = str + "没有找到“" + this.Method.MethodName + "”方法";
                InternalSystemException ex6 = new InternalSystemException(str + ".", this, null);
                this.OnError(ex6);
                invokeResult.AddError(ex6, null);
                return invokeResult;
            }
            try
            {
                obj = this.JobClassType.GetMethod(this.Method.MethodName).Invoke(baseJob, (list.Count > 0) ? list.ToArray() : null);
            }
            catch (Exception innerException4)
            {
                Exception ex7 = new Exception(string.Format("执行业务类“{0}”的“{1}”（{2}）方法时出现错误。", baseJob.GetType().FullName, this.Method.MethodName, this.FunctionSign), innerException4);
                this.OnError(ex7);
                invokeResult.AddError(ex7, null);
            }
            finally
            {
                if (this.JobServiceMode == JobServiceMode.Dynamic)
                {
                    try
                    {
                        if (baseJob != null)
                        {
                            baseJob.Dispose();
                        }
                        baseJob = null;
                    }
                    catch
                    {
                    }
                }
            }
            if (obj != null && obj.GetType().TypeAs(typeof(IResultData)))
            {
                invokeResult.ReceiveResult((IResult)obj);
                invokeResult.IsVoid = false;
                try
                {
                    if (((IResultData)obj).Data != null)
                    {
                        invokeResult.DataType = ((IResultData)obj).Data.GetType().AssemblyQualifiedName;
                    }
                    invokeResult.Json = JsonConvertHelper.ToJson(((IResultData)obj).Data);
                    goto IL_54C;
                }
                catch (Exception innerException5)
                {
                    InternalSystemException ex8 = new InternalSystemException("将业务执行的结果数据转换成json数据时发生戳我。", this, innerException5);
                    this.OnError(ex8);
                    invokeResult.AddError(ex8, null);
                    goto IL_54C;
                }
            }
            if (obj != null && obj.GetType().TypeAs(typeof(IResult)))
            {
                invokeResult.ReceiveResult((IResult)obj);
            }
        IL_54C:
            if (debug)
            {
                stopwatch.Stop();
                invokeResult.CallMilliseconds = stopwatch.ElapsedMilliseconds;
            }
            return invokeResult;
        }


    }
}
